#region imported Namespaces
using System;
using System.Data;
using System.Data.SqlClient;

using BO = PHSRAG.Insight21.BusinessObjects;
using DataAccess = PHSRAG.Utility.DataAccess;
using ICachePolicy = PHSRAG.Insight21.Policy.ICachePolicy;
using PerDetailConstants = PHSRAG.Insight21.Personnel.Constants.PersonnelDetailsConstants;
using ArgumentIndex = PHSRAG.Insight21.Personnel.PersonnelDetailsArgumentIndex;
#endregion


namespace PHSRAG.Insight21.Personnel
{
	#region Class PersonnelDetails
	/// <summary>
	/// The Personnel details class supports loading of the personnel
	/// details data for a given job map id and fiscal year.
	/// It contains the salaries, distributionperiods and salarydistributions
	/// These will be loaded along with the personnel demog info.
	/// It supports saving/updating comment and harvard title for an employee job map id
	/// </summary>
	public class PersonnelDetails:BO.BusinessObject
	{
		#region Constants
		private const string PersonnelDetailsKey		= "PersonnelDetails_23537764-9D81-4EE9-8779-B0C82B8C4A97";
		//Constants to hold table and row indices
		private const int PersonnelDemogInfoTableIndex	= 0;
		private const int FirstRowIndex					= 0;
		private const int CommentsTableIndex			= 1;
		#endregion

		#region Enumerations (Private)
		//Enumerate the argument indeces used in the update comment stored procedure
		private enum UpdateCommentArgumentIndex
		{
			DomainUserID,
			FiscalYearID,
			EmployeeJobMapID
		}
		//Enumerate the argument indeces used in the update title stored procedure
		private enum UpdateTitleArgumentIndex
		{
			DomainUserID,
			EmployeeJobMapID
		}
		#endregion

		#region Instance Variables
		private Salaries salarys;
		private DistributionPeriods distribPeriods;
		private SalaryDistributions salaryDistribs;
		#endregion

		#region Class methods
		/// <summary>
		/// Get the fiscal year list associated with the given employee job map id
		/// </summary>
		/// <param name="domainUserID">The domain user id of the current user</param>
		/// <param name="employeeJobMapID">The employee job map id</param>
		/// <returns>DataTable with the fiscal year list</returns>
		public static DataTable GetFiscalYearList(int domainUserID,int employeeJobMapID)
		{
			return Utility.DataAccess.GetDataTable
				(Utility.DataAccess.GetConnectionString()
				,Constants.GetFiscalYearsSPROCName
				,Utility.DataAccess.BuildSqlParameterArray
				("@domainUserID",SqlDbType.Int,domainUserID
				,"@employeeJobMapID",SqlDbType.Int,employeeJobMapID));
		}

		#endregion

		#region Public Properties
		/// <summary>
		/// Get the key to be used in all caching operations for this instance of the object.
		/// </summary>
		public static string CacheKey	{ get { return PersonnelDetailsKey; } }
		/// <summary>
		/// Get the employee number for the employee
		/// Return empty string if the employee has no employee number associated
		/// </summary>
		public string EmployeeID
		{
			get
			{
				object employeeID = DataContainer.Tables[PerDetailConstants.PersonnelDetailsTableName].
					Rows[FirstRowIndex][PerDetailConstants.EmployeeNumberColumnName];
				return (employeeID == DBNull.Value)?string.Empty:employeeID.ToString();
			}
		}
		/// <summary>
		/// Get the name of the employee (LastName, FirstName)
		/// It is a non nullable field.
		/// </summary>
		public string EmployeeName
		{
			get
			{
				return DataContainer.Tables[PerDetailConstants.PersonnelDetailsTableName].
					Rows[FirstRowIndex][PerDetailConstants.EmployeeNameColumnName].ToString();
			}
		}
		/// <summary>
		/// Get the job code associated with the employee.
		/// Return an empty string if no job code associated.
		/// </summary>
		public string JobCode
		{
			get
			{
				object jobCode = DataContainer.Tables[PerDetailConstants.PersonnelDetailsTableName].
					Rows[FirstRowIndex][PerDetailConstants.JobCodeColumnName];
				return (jobCode == DBNull.Value)?string.Empty:jobCode.ToString();
			}
		}
		/// <summary>
		/// Get the HR Department to which this employee belongs
		/// Return an empty string if there is no HR Dept associated with the employee
		/// </summary>
		public string HRDepartment
		{
			get
			{
				object hrDept = DataContainer.Tables[PerDetailConstants.PersonnelDetailsTableName].
					Rows[FirstRowIndex][PerDetailConstants.HRDepartmentColumnName];
				return (hrDept == DBNull.Value)?string.Empty:hrDept.ToString();
			}
		}
		/// <summary>
		/// Get the employee's status. 
		/// Return an empty string if the employee has no Status assocaited with him.
		/// </summary>
		public string Status
		{
			get
			{
				object status = DataContainer.Tables[PerDetailConstants.PersonnelDetailsTableName].
					Rows[FirstRowIndex][PerDetailConstants.StatusColumnName];
				return (status == DBNull.Value)?string.Empty:status.ToString();
			}
		}
		/// <summary>
		/// Get the job title of the employee for this job map id
		/// It is a non nullable field.
		/// </summary>
		public string Title
		{
			get
			{
				return DataContainer.Tables[PerDetailConstants.PersonnelDetailsTableName].
					Rows[FirstRowIndex][PerDetailConstants.TitleColumnName].ToString();
			}
		}
		/// <summary>
		/// Get the RecordNumber assocaited with the employee
		/// It is a non nullable field.
		/// </summary>
		public string RecordNumber
		{
			get
			{
				return DataContainer.Tables[PerDetailConstants.PersonnelDetailsTableName].
					Rows[FirstRowIndex][PerDetailConstants.RecordNumberColumnName].ToString();
			}
		}
		/// <summary>
		/// Get/Set the External title associated with the employee for the given job map id
		/// Return an empty string if there is no external title associated
		/// Set the value to the appropriate column in the datacontainer
		/// </summary>
		public string HarvardTitle
		{
			get
			{
				object harvardTitle = DataContainer.Tables[PerDetailConstants.PersonnelDetailsTableName].
					Rows[FirstRowIndex][PerDetailConstants.HarvardTitleColumnName];
				return (harvardTitle == DBNull.Value)?string.Empty:harvardTitle.ToString();
			}
			set
			{
				DataContainer.Tables[PerDetailConstants.PersonnelDetailsTableName].
					Rows[FirstRowIndex][PerDetailConstants.HarvardTitleColumnName] = value;
			}
		}
		/// <summary>
		/// Get/Set comment assocaited with the employee's salary distribution for a particular fiscal year
		/// Return an empty string if there are no comments.
		/// Set the value to the appropriate column in the datacontainer.
		/// If there are no rows already present add a new row
		/// </summary>
		public string Comment
		{
			get
			{
				object comment = (DataContainer.Tables[PerDetailConstants.CommentsTableName].Rows.Count == 1)
					?DataContainer.Tables[PerDetailConstants.CommentsTableName].Rows[FirstRowIndex]
					[PerDetailConstants.CommentColumnName]
					:DBNull.Value;
				return (comment == DBNull.Value)?string.Empty:comment.ToString();
			}
			set
			{
				if(DataContainer.Tables[PerDetailConstants.CommentsTableName].Rows.Count == 0)
					DataContainer.Tables[PerDetailConstants.CommentsTableName].Rows.
						Add(DataContainer.Tables[PerDetailConstants.CommentsTableName].NewRow());
				
				DataContainer.Tables[PerDetailConstants.CommentsTableName].
					Rows[FirstRowIndex][PerDetailConstants.CommentColumnName] = value;
			}	
		}
		/// <summary>
		/// Get/Set user who last edited the comment assocaited with the employee's
		/// salary distribution for a particular fiscal year
		/// Return an empty string if there is no edited by value.
		/// Set the value to the appropriate column in the datacontainer
		/// </summary>
		public string CommentEditedBy
		{
			get
			{
				object commentEditedBy = (DataContainer.Tables[PerDetailConstants.CommentsTableName].Rows.Count == 1)
					?DataContainer.Tables[PerDetailConstants.CommentsTableName].Rows[FirstRowIndex]
					[PerDetailConstants.CommendEditedByColumnName]
					:DBNull.Value;
				return (commentEditedBy == DBNull.Value)?string.Empty:commentEditedBy.ToString();
			}
			set
			{
				DataContainer.Tables[PerDetailConstants.CommentsTableName].
					Rows[FirstRowIndex][PerDetailConstants.CommendEditedByColumnName] = value;
			}
		}
		/// <summary>
		/// Get/Set th last date on which the comment assocaited with the employee's
		/// salary distribution for a particular fiscal year was edited
		/// Return an empty string if there is no editdate value.
		/// Set the value to the appropriate column in the datacontainer
		/// </summary>
		public string CommentEditDate
		{
			get
			{
				object commentEditDate = (DataContainer.Tables[PerDetailConstants.CommentsTableName].Rows.Count == 1)
					?DataContainer.Tables[PerDetailConstants.CommentsTableName].Rows[FirstRowIndex]
					[PerDetailConstants.CommentEditDateColumnName]
					:DBNull.Value;
				return (commentEditDate == DBNull.Value)?
					string.Empty:((DateTime)commentEditDate).ToString("MM/dd/yyyy");
			}
			set
			{
				DataContainer.Tables[PerDetailConstants.CommentsTableName].
					Rows[FirstRowIndex][PerDetailConstants.CommentEditDateColumnName] = value;
			}
		}
		/// <summary>
		/// Get the flag denoting whether the employee is managed or unmanaged
		/// If the flag is true the employee is managed
		/// </summary>
		public bool IsManagedEmployee
		{
			get
			{
				return (bool)(DataContainer.Tables[PerDetailConstants.PersonnelDetailsTableName].
					Rows[FirstRowIndex][PerDetailConstants.IsManagedEmployeeColumnName]);
			}
		}
		#endregion

		#region Private properties
		/// <summary>
		/// Get the fiscal year to which this personnel demog data belongs to
		/// </summary>
		private int FiscalYear
		{
			get
			{
				return (int)DataContainer.Tables[PerDetailConstants.PersonnelDetailsTableName].
					Rows[FirstRowIndex][PerDetailConstants.FiscalYearColumnName];
			}
		}
		#endregion

		#region Public Contained objects
		/// <summary>
		/// Get the contained Salarys object
		/// </summary>
		public Salaries Salarys
		{
			get{return salarys;}
		}
		/// <summary>
		/// Get the contained DistributionPeriods object
		/// </summary>
		public DistributionPeriods DistribPeriods
		{
			get{return distribPeriods;}
		}
		/// <summary>
		/// Get the contained SalaryDistributions object
		/// </summary>
		public SalaryDistributions SalaryDistribs
		{
			get{return salaryDistribs;}
		}
		#endregion

		#region Constructor
		/// <summary>
		/// Intializes the base class with the prevalent cache policy
		/// </summary>
		/// <param name="cachePolicy">The prevalent cache policy</param>
		public PersonnelDetails (): base (null)
		{
		}		
		#endregion

		#region BusinessObject Methods
		/// <summary>
		/// Load the personnel details data accessible to the currently logged in user
		/// For load the domain user id,employee job map id and fiscal year id are mandatory
		/// This also loads the contained objects (Salarys, DistributionPeriods, SalaryDistributions)
		/// </summary>
		/// <param name="connectionString">The database connection string</param>
		/// <param name="args">Is expected to contain 3 arguments -
		/// DomainUserID,EmployeeJobMapID and FiscalYearID</param>
		public override void Load(string connectionString, params object[] args)
		{
			try
			{
				if (args.Length != 3)
					throw new Exception
						("Personnel details load requires the domainuserid,a jobmapid and a fiscalyearid");
			
				DataContainer = DataAccess.GetDataSet(
					connectionString
					,PerDetailConstants.GetPersonnelDetailsSPROCName
					,Utility.DataAccess.BuildSqlParameterArray(
					"@domainUserId",SqlDbType.Int,args[(int)ArgumentIndex.DomainUserID]
					,"@employeeJobMapId", SqlDbType.Int, args[(int)ArgumentIndex.EmployeeJobMapID]
					,"@fiscalYearId",SqlDbType.Int,args[(int)ArgumentIndex.FiscalYearID]));
			
			
				if(DataContainer.Tables.Count >= 1)
                    DataContainer.Tables[PersonnelDemogInfoTableIndex].TableName = 
						PerDetailConstants.PersonnelDetailsTableName;				
				else
					throw new Exception(@"No personnel details information found for the user");

				salarys = new Salaries(DataContainer,CachePolicy);
				salarys.Load(connectionString
					,args[(int)ArgumentIndex.DomainUserID]
					,args[(int)ArgumentIndex.EmployeeJobMapID]);

				distribPeriods = new DistributionPeriods(DataContainer,CachePolicy);
				distribPeriods.Load(connectionString
					,args[(int)ArgumentIndex.DomainUserID]
					,args[(int)ArgumentIndex.EmployeeJobMapID]
					,args[(int)ArgumentIndex.FiscalYearID]
					,FiscalYear);

				salaryDistribs = new SalaryDistributions(DataContainer,CachePolicy);
				salaryDistribs.Load(connectionString
					,args[(int)ArgumentIndex.DomainUserID]
					,args[(int)ArgumentIndex.EmployeeJobMapID]
					,args[(int)ArgumentIndex.FiscalYearID]);

				if(IsManagedEmployee)
					DataContainer.Tables[CommentsTableIndex].TableName = 
						PerDetailConstants.CommentsTableName;
			}
			catch(Exception ex)
			{
				throw new Exception(@"Error in loading personnel details",ex);
			}			
		}
		#endregion

		#region Instance methods (Public)
		/// <summary>
		///	Save the comments asociated with the details for this employee in the given fiscal year
		///	Throw an exception if any error in the save operation
		/// </summary>
		/// <param name="connectionString">Database connection string</param>
		/// <param name="domainUserID">The domain user id of the logged in user</param>
		/// <param name="employeeJobMapID">The employee job map id</param>
		
		/// <summary>
		///	Save the comments asociated with the details for this employee in the given fiscal year
		///	Throw an exception if any error in the save operation
		/// </summary>
		/// <param name="connectionString">Database connection string</param>
		/// <param name="args">Is expected to contain 3 arguments -
		/// DomainUserID,EmployeeJobMapID and FiscalYearID</param>
		public void SaveComments(string connectionString,params object[] args)
		{
			try
			{
				Utility.DataAccess.ExecuteNonQuery(connectionString
					,PerDetailConstants.UpdateCommentSPROCName
					,Utility.DataAccess.BuildSqlParameterArray
					("@domainUserID",SqlDbType.Int,args[(int)UpdateCommentArgumentIndex.DomainUserID]
                    ,"@fiscalYearID",SqlDbType.Int,args[(int)UpdateCommentArgumentIndex.FiscalYearID]
					,"@employeeJobMapID",SqlDbType.Int,args[(int)UpdateCommentArgumentIndex.EmployeeJobMapID]
					,"@comments",SqlDbType.VarChar,Comment
					,"@editedBy",SqlDbType.VarChar,CommentEditedBy
					,"@editDate",SqlDbType.DateTime,CommentEditDate));
			}
			catch(Exception ex)
			{
				throw ex;
			}
		}
		/// <summary>
		/// Update the harvard title associated with the employee job map id
		///	Throw an exception if any error in the update operation
		/// </summary>
		/// <param name="connectionString">Database connection string</param>
		/// <param name="args">Is expected to contain 2 arguments DomainUserID & EmployeeJobMapID</param>
		public void UpdateHarvardTitle(string connectionString,params object[] args)
		{
			try
			{
				Utility.DataAccess.ExecuteNonQuery(connectionString
					,PerDetailConstants.UpdateHarvardTitleSPROCName
					,Utility.DataAccess.BuildSqlParameterArray
					("@domainUserID",SqlDbType.Int,args[(int)UpdateTitleArgumentIndex.DomainUserID]
					,"@employeeJobMapID",SqlDbType.Int,args[(int)UpdateTitleArgumentIndex.EmployeeJobMapID]
					,"@harvardTitle",SqlDbType.VarChar,HarvardTitle));
			}
			catch(Exception ex)
			{
				throw new Exception(@"Error in updating harvard title",ex);
			}
		}
		#endregion
	}
	#endregion
}